package com.note.user.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.note.common.constants.ResponseCodeConstants;
import com.note.common.domain.User;
import com.note.common.dto.MinioUploadDto;
import com.note.common.dto.UserDto;
import com.note.common.dto.UserModifyDto;
import com.note.common.enums.LogEnum;
import com.note.common.enums.ResponseEnum;
import com.note.common.interfaces.SystemLog;
import com.note.common.vo.ResponseVo;
import com.note.config.config.CustomBlockHandler;
import com.note.config.constants.GatewayConstants;
import com.note.user.config.MinioConfig;
import com.note.user.dao.mapper.MinioMapper;
import com.note.user.service.UserInfoService;
import com.note.user.service.UserModifyService;
import com.note.user.service.internal.MinioFileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.Arrays;
import java.util.Locale;

/**
 * @Package：com.note.user.controller
 * @Name：UserInfoController
 * @Author：热伊木
 * @Email：uyevan@163.com
 * @Date：2023-12-17-19:52
 * @Description：用户信息获取
 */
@Slf4j
@Validated
@Controller
@RequestMapping("/user")
@Tag(name = "UserInfoController", description = "用户个人信息获取接口")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserModifyService userModifyService;

    /*Minio源*/
    @Value("${minio.endpoint}")
    private String ENDPOINT;

    @Value("${minio.bucketName}")
    private String BUCKET_NAME;

    @Value("${minio.accessKey}")
    private String ACCESS_KEY;

    @Value("${minio.secretKey}")
    private String SECRET_KEY;

    @Value("${minio.file.extensions}")
    private String[] fileExtensions;

    @Value("${minio.oss-url}")
    private String OSS_URL;

    @Autowired
    private MinioMapper minioMapper;


    @Autowired
    private MinioFileService minioFileService;

    @Autowired
    private MinioConfig minioConfig;


    @ResponseBody
    @GetMapping("/info")
    @SystemLog(type = LogEnum.CHECK_LOG)
    //Sentinel流控
    @SentinelResource(value = "getUserInfo",
            blockHandler = "blockHandleException",
            blockHandlerClass = CustomBlockHandler.class,
            fallbackClass = CustomBlockHandler.class,
            fallback = "fallBackHandle")
    @Operation(summary = "info", description = "获取用户信息接口（username）")
    @Parameters(@Parameter(name = "username", description = "用户名", required = true, in = ParameterIn.QUERY))
    public ResponseVo getUserInfo(@RequestParam @NotBlank(message = "用户名不能为空") String username) {
        UserDto userDto = new UserDto();
        userDto.setUsername(username);
        int validateUserCode = userInfoService.validateUser(userDto);
        return switch (validateUserCode) {
            case ResponseCodeConstants.USER_NOT_FOUND -> new ResponseVo(ResponseEnum.USER_NOT_FOUND);
            case ResponseCodeConstants.USER_BANNED -> new ResponseVo(ResponseEnum.USER_BANNED);
            case ResponseCodeConstants.LOGIN_SUCCESS ->
                    new ResponseVo(ResponseEnum.SUCCESS, userInfoService.getUserIndo(userDto));
            default -> new ResponseVo(ResponseEnum.FAIL);
        };
    }

    @ResponseBody
    @SystemLog(type = LogEnum.REFRESH_LOG)
    @PostMapping("/modify")
    @SentinelResource(value = "modifyUserInfo",
            blockHandlerClass = CustomBlockHandler.class,
            blockHandler = "blockHandleException",
            fallbackClass = CustomBlockHandler.class,
            fallback = "fallBackHandle")
    @Operation(summary = "modify", description = "修改用户信息接口")
    @Parameters({
            @Parameter(name = "username", description = "用户名", required = true, in = ParameterIn.QUERY),
            @Parameter(name = "nickname", description = "昵称", required = true, in = ParameterIn.QUERY),
            @Parameter(name = "avatar", description = "头像", required = true, in = ParameterIn.QUERY)
    })
    public ResponseVo modifyUserInfo(
            @Valid UserModifyDto userModifyDto,
            /*@RequestPart("avatar") 如果 null 会报错*/ MultipartFile avatar) {
        try {
            MinioUploadDto minioUploadDto = new MinioUploadDto("", "", "");
            if (avatar != null) {
                //TODO 验证文件大小
                long size = avatar.getSize();
                if (size == 0L) {
                    return ResponseVo.fail("禁止上传空文件,稍后重试");
                }
                //TODO 验证无后缀文件
                String filename = avatar.getOriginalFilename();
                int index = filename.lastIndexOf(".");
                if (index == -1) {
                    return ResponseVo.fail("禁止上传无后缀文件,稍后重试");
                }
                //TODO 验证文件后缀
                String etc = filename.substring(index + 1);//文件后缀
                if (!Arrays.asList(fileExtensions).contains(etc.toLowerCase(Locale.ROOT))) {
                    return ResponseVo.fail("禁止上传该类型文件,稍后重试");
                }
                // TODO 临存输出流
                InputStream inputStream = avatar.getInputStream();
                minioConfig.uploadFile(avatar, userModifyDto, minioUploadDto, inputStream);
            }
            if (userModifyService.modifyUserInfo(userModifyDto.getUsername(), userModifyDto.getNickname(), minioUploadDto.getUrl(), minioUploadDto.getFileMd5())) {
                return ResponseVo.success("数据更新成功");
            }
            return ResponseVo.fail("更新失败,稍后重试");
        } catch (Exception e) {
            log.error("上传错误:{}", e);
            throw new RuntimeException("上传错误,稍后重试");
        }
    }

    /**
     * 内部接口
     *
     * @param username
     * @param internalKey
     * @return
     */
    @ResponseBody
    @GetMapping("/internal/fetchUserInfoGateway/{username}/{internalKey}")
    @Operation(summary = "fetchUserInfoGateway", description = "内部网关调用获取用户信息")
    @Parameters({
            @Parameter(name = "username", description = "用户名", required = true, in = ParameterIn.QUERY),
            @Parameter(name = "internalKey", description = "校验密钥", required = true, in = ParameterIn.QUERY),
    })
    public User fetchUserInfoGateway(
            @PathVariable("username") @NotBlank(message = "Username not null.") String username,
            @PathVariable("internalKey") @NotBlank(message = "InternalKey not null.") String internalKey) {
        if (!internalKey.equals(GatewayConstants.INTERNAL_KEY)) {
            return null;
        }
        UserDto userDto = new UserDto();
        userDto.setUsername(username);
        User user = userInfoService.getUserIndo(userDto);
        /*log.info("User:{}", user);*/
        return user;
    }

}
